<html>
<head>

<title>Groovy Goodness: Use GroovyWS to Access SOAP Web Services (Part 2)</title>

<script language="javascript" src="scripts/shCore.js"></script> 
<script language="javascript" src="scripts/shLegacy.js"></script> 
<script language="javascript" src="scripts/shBrushJava.js"></script> 
<script language="javascript" src="scripts/shBrushXml.js"></script> 
<script language="javascript" src="scripts/shBrushJScript.js"></script> 
<script language="javascript" src="scripts/shBrushGroovy.js"></script> 
<script language="javascript" src="scripts/shBrushPlain.js"></script> 
<script language="javascript" src="scripts/shBrushBash.js"></script> 
 
<link href="styles/reset.css" rel="stylesheet" type="text/css" />
<link href="styles/shCore.css" rel="stylesheet" type="text/css" />
<link type="text/css" rel="stylesheet" href="styles/shThemeRDark.css"/>
<link href="styles/blog.css" rel="stylesheet" type="text/css" />

</head>
<body>

<a href="index.html">Back to index</a>

<h3 class="post-title">Groovy Goodness: Use GroovyWS to Access SOAP Web Services (Part 2)</h3>

<div class="post">
<p>In a <a href="http://mrhaki.blogspot.com/2010/11/groovy-goodness-use-groovyws-to-access.html">previous post</a> we learned how to create a SOAP web service with the XFire plugin in Grails. The generated WSDL defined that the properties of our objects could be null by default and the minimum occurence is 0. And because of this we must work with <code>JAXBElement</code> objects to get the real object values. In this post we change the property mapping so the properties cannot be null and have a minimum occurence of 1. And then we can change our client code and deal with the object values directly instead of via a <code>JAXBElement</code> object.</p>

<b>Grails SOAP web service</b>

<p>We can change the default mapping of our objects that is generated by the XFire plugin. We must add an Aegis mapping XML file to our classpath and in this file we can define the custom mapping we want to apply. The name of the file is <code>&lt;ClassName&gt;.aegis.xml</code> and must be in the same package as the class we are writing the custom mapping for. If we add the XML files to the <code>src/java</code> directory of our Grails application then the files will be copied to the classpath automatically.</p>
<p>After we have created the XML mapping files we must add an extra runtime dependency. So we change the <code>grails-app/conf/BuildConfig.groovy</code> file and add a dependency to Jaxen, because this is needed to make the custom mapping work.</p>
<pre class="brush:groovy">
&lt;!-- File: src/java/com/mrhaki/groovyws/server/Author.aegis.xml --&gt;
&lt;mappings&gt;
    &lt;mapping&gt;
        &lt;property name="name" minOccurs="1" nillable="false"/&gt;
        &lt;property name="blogItems" minOccurs="1" componentType="com.mrhaki.groovyws.server.BlogItem"/&gt;
    &lt;/mapping&gt;
&lt;/mappings&gt;
</pre>
<pre class="brush:groovy">
&lt;!-- File: src/java/com/mrhaki/groovyws/server/BlogItem.aegis.xml --&gt;
&lt;mappings&gt;
    &lt;mapping&gt;
        &lt;property name="title" minOccurs="1" nillable="false"/&gt;
        &lt;property name="text" minOccurs="1" nillable="false"/&gt;
    &lt;/mapping&gt;
&lt;/mappings&gt;
</pre>
<pre class="brush:groovy">
&lt;!-- File: src/java/com/mrhaki/groovyws/server/SearchRequest.aegis.xml --&gt;
&lt;mappings&gt;
    &lt;mapping&gt;
        &lt;property name="authorName" minOccurs="1" nillable="false"/&gt;
    &lt;/mapping&gt;
&lt;/mappings&gt;
</pre>
<pre class="brush:groovy">
// File: grails-app/conf/BuildConfig.groovy
grails.project.class.dir = "target/classes"
grails.project.test.class.dir = "target/test-classes"
grails.project.test.reports.dir = "target/test-reports"
grails.project.dependency.resolution = {
    inherits("global") {
    }
    log "warn"
    repositories {
        grailsPlugins()
        grailsHome()
        grailsCentral()
        mavenCentral()
    }
    dependencies {
        runtime('jaxen:jaxen:1.1.1') {
            transitive = false
        }
    }
}
</pre>
<p>We can run our Grails application with <code>$ grails run-app</code> and open the URL <code>http://localhost:8080/server/services/blog?wsdl</code> to see the changes in the generated WSDL file.</p>

<b>GroovyWS Client</b>

<p>Because the definition of our SOAP web service is changed we can also change the client code. We now no longer have use <code>JAXBElement</code> objects, so our code is much cleaner. We can access the object types directly. For example for the dynamic <code>SearchRequest</code> object we can set the  <code>authorName</code> property directly. In our old client code we had to create a <code>JAXBElement</code> object to set the value.</p>
<pre class="brush:groovy">
package com.mrhaki.groovyws.client

import groovyx.net.ws.WSClient

class BlogWSClient {

    String wsdlUrl

    def proxy

    def findAuthor(String name) {
        createProxy()
        def searchRequest = createSearchRequest(name)
        proxy.findAuthor searchRequest
    }

    private def createSearchRequest(String name) {
        def searchRequest = proxy.create('com.mrhaki.groovyws.server.SearchRequest')
        searchRequest.authorName = name
        searchRequest
    }

    private void createProxy() {
        if (!proxy) {
            proxy = new WSClient(wsdlUrl, this.class.classLoader)
            proxy.initialize()
        }
    }

}
</pre>
<pre class="brush:groovy">
package com.mrhaki.groovyws.client

import spock.lang.Specification

class BlogWSClientSpec extends Specification {

    def client = new BlogWSClient(wsdlUrl: 'http://localhost:8080/server/services/blog?wsdl')

    def "get author with name mrhaki and two blog items"() {
        when:
        def author = client.findAuthor('mrhaki')

        then:
        'mrhaki' == author.name
        def arrayOfBlogItems = author.blogItems
        def blogItems = arrayOfBlogItems.blogItem
        2 == blogItems.size()
        'Title1' == blogItems[0].title
        'Title2' == blogItems[1].title
        'Sample blogitem one.' == blogItems[0].text
        'Sample blogitem two.' == blogItems[1].text
    }

}
</pre>
<p>In the <a href="http://mrhaki.blogspot.com/2010/11/groovy-goodness-use-groovyws-to-access_15.html">next post</a> we see how we can add logging interceptors to our client so we can see the input and output from the invocation of the SOAP web service.</p
</div>

<script language="javascript"> 
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.config.clipboardSwf = 'scripts/clipboard.swf';
SyntaxHighlighter.defaults['first-line'] = 0;
SyntaxHighlighter.defaults['auto-links'] = false;
SyntaxHighlighter.all();
dp.SyntaxHighlighter.HighlightAll('code');
</script>

</body>
</html>